﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
using System;
using System.Reflection;
using BrainTechLLC.ThreadSafeObjects;
using LinFu.AOP.Interfaces;

namespace BrainTechLLC
{
	[Serializable, AttributeUsage(AttributeTargets.Method)]
	public class InvokeIfThenElseAttribute : IfCaseAttribute, IReadableAttribute
	{
		public InvokeIfThenElseAttribute(string ifMethod, string thenMethod, string elseMethod,
			string ifMethodAfter, string thenMethodAfter, string elseMethodAfter)
			: base(ifMethod, thenMethod, elseMethod, ifMethodAfter, thenMethodAfter, elseMethodAfter) { }
	}

	[Serializable, AttributeUsage(AttributeTargets.Method)]
	public class IfCaseAttribute : Attribute, IReadableAttribute
	{
		public string IfMethodName { get; set; }
		public string ThenMethodName { get; set; }
		public string ElseMethodName { get; set; }
		public string IfMethodNameAfter { get; set; }
		public string ThenMethodNameAfter { get; set; }
		public string ElseMethodNameAfter { get; set; }

		public object Value { get { return IfMethodName; } }

		public IfCaseAttribute(string ifMethod, string thenMethod, string elseMethod,
			string ifMethodAfter, string thenMethodAfter, string elseMethodAfter)
		{
			IfMethodName = ifMethod;
			ThenMethodName = thenMethod;
			ElseMethodName = elseMethod;
			IfMethodNameAfter = ifMethodAfter;
			ThenMethodNameAfter = thenMethodAfter;
			ElseMethodNameAfter = elseMethodAfter;
		}

		protected void GetIfThenElseMethodsBefore(Type t, out MethodInfo ifDel, out MethodInfo thenDel, out MethodInfo elseDel)
		{
			ifDel = Lookups.IfLookup.Get(t.DotMethodName(IfMethodName), v => t.GetMethod(IfMethodName));
			thenDel = null; elseDel = null;

			if (!string.IsNullOrEmpty(ThenMethodName))
				thenDel = Lookups.ThenLookup.Get(t.DotMethodName(ThenMethodName), v => t.GetMethod(ThenMethodName));

			if (!string.IsNullOrEmpty(ElseMethodName))
				elseDel = Lookups.ElseLookup.Get(t.DotMethodName(ElseMethodName), v => t.GetMethod(ElseMethodName));
		}

		protected void GetIfThenElseMethodsAfter(Type t, out MethodInfo ifDel, out MethodInfo thenDel, out MethodInfo elseDel)
		{
			ifDel = Lookups.IfLookup.Get(t.DotMethodName(IfMethodNameAfter), v => t.GetMethod(IfMethodNameAfter));
			thenDel = null; elseDel = null;

			if (!string.IsNullOrEmpty(ThenMethodNameAfter))
				thenDel = Lookups.ThenLookup.Get(t.DotMethodName(ThenMethodNameAfter), v => t.GetMethod(ThenMethodNameAfter));

			if (!string.IsNullOrEmpty(ElseMethodNameAfter))
				elseDel = Lookups.ElseLookup.Get(t.DotMethodName(ElseMethodNameAfter), v => t.GetMethod(ElseMethodNameAfter));
		}

		public void DoWorkBefore(IInvocationContext context, object thisObject)
		{
			Type t = thisObject.GetType();
			MethodInfo ifDel, thenDel, elseDel;
			GetIfThenElseMethodsBefore(t, out ifDel, out thenDel, out elseDel);

			if (ifDel == null)
			{
				thenDel.InvokeIfNotNull(thisObject, context);
			}
			else
			{
				object result = ifDel.Invoke(thisObject, new object[] { context });

				if (Convert.ToBoolean(result) == true)
					thenDel.InvokeIfNotNull(thisObject, context);
				else
					elseDel.InvokeIfNotNull(thisObject, context);
			}
		}

		public void DoWorkAfter(IInvocationContext context, object thisObject)
		{
			Type t = thisObject.GetType();
			MethodInfo ifDel, thenDel, elseDel;
			GetIfThenElseMethodsAfter(t, out ifDel, out thenDel, out elseDel);

			if (ifDel == null)
			{
				thenDel.InvokeIfNotNull(thisObject, context);
			}
			else
			{
				object result = ifDel.Invoke(thisObject, new object[] { context });

				if (Convert.ToBoolean(result) == true)
					thenDel.InvokeIfNotNull(thisObject, context);
				else
					elseDel.InvokeIfNotNull(thisObject, context);
			}
		}
	}
}

